#include <iostream>
#include <vector>
#include <fstream>
#include <stdlib.h>
#include "funcionesHash.cpp"
#define FUNCIONES_HASH 16

using namespace std;

int** generarMatrizHashMin(int numeroDeDocsTotales) { 
  
  int** matrizHashMin = (int**) malloc (sizeof(int*)*FUNCIONES_HASH); // numero de filas = cant de func de hash
  for(int i=0; i< FUNCIONES_HASH; i++) {
		matrizHashMin[i]= (int *)malloc(sizeof(int)*numeroDeDocsTotales);
		for(int j=0; j<numeroDeDocsTotales; j++) {
			matrizHashMin[i][j]= MAXIMO;
		}
    
  }
  /*
  for (int u = 0; u<FUNCIONES_HASH; u++) {
		for (int w = 0; w<numeroDeDocsTotales; w++) {
			cout << matrizHashMin[u][w];
	}
	cout << endl;
  }
  */
  return matrizHashMin;
}
//necesito un vector donde esten todas las funciones de hashing
void procesarFrecuencia(float lector,int** matrizHashMin, char aux[6], int doc) {
	for (int fhs = 0; fhs < FUNCIONES_HASH; fhs++) {
		int hashing = hashingTermino(fhs, aux);
		if (matrizHashMin[fhs][doc] > hashing) matrizHashMin[fhs][doc] = hashing;
	}
}
// voy leyendo la granMatriz por filas. para cada fila voy leyendo cada uno de sus elementos. si son distintos de cero
// entonces al termino(columna) donde esta ese elemento, le aplico las funciones de hashing 0 a 15 modificando la matriz
// en los casos en que el resultado sea menor que lo que ya hay en ese lugar.
// numeroTotalTerminos = numero total de terminos en la matrizgrande
void procesarGranMatriz (int numeroDeDocsTotales, int numeroTotaldeTerminos, string pathGranMatriz, int** matrizHashMin) { 
  
  char aux[6] = "";
  float lector = 0.0;
  
  std::fstream fs (pathGranMatriz.data(), std::fstream::in);
  for (int termino = 0; termino < numeroTotaldeTerminos; termino++) {
		fs.read(aux, sizeof(char[6]));
		std::cout << "Reading char[6]: " << std::fixed << aux << std::endl;
		for (int doc = 0; doc < numeroDeDocsTotales; doc++) {
			fs.read((char*)&lector, sizeof(float));
			std::cout << "Reading floating point number: " << std::fixed << lector << std::endl;
			if (lector) procesarFrecuencia(lector, matrizHashMin, aux, doc);
		}
  }
  fs.close();
  
  //salgo de aca con toda la matriz de hashmin terminada y optimizada lista para hacer los clusters.
  
  // while (!EOF) 
  //  leer un char[6] y numeroDeDocsTotales float's (fila j)
	// si el float (i) != 0
	// se ejecutan las funciones de hash para el termino char[6] y se modifica la columna i toda en caso de ser < el hashing
  
  /*
  fseek(granMatriz,0,SEEK_SET); // abrir
   
  while (!feof(granMatriz)){
  
    fread( &unaFilaAuxiliar,sizeof(struct filaGranMatriz),1,granMatriz);
    
    for(int i=0; i<FUNCIONES_HASH; i++){
      
      // verifico si la frecuencia es distinta de 0, si es asi modifico la fila de matriz de hashmin
      
      if(unaFilaAuxiliar.frecuenciasDocumentos[i]!=0) {
	
		for(int j=0; j<numeroDeDocsTotales; j++){
	  
			int hashing = hashingTermino(j,unaFilaAuxiliar.palabra);
	  
			// verifico que el hashing sea menor que el que estaba en la matriz
	  
			if(matrizHashMin[i][j] > hashing){
	    
			matrizHashMin[i][j] = hashing;
			}
		}
      }
    }
  }
  */
}

class Cluster {
	public:
	vector<int> docs;
};



// suponiendo que hay 48 funciones de hashing. 48 es divisible por 2,3,4,6,8,12,16 y 24. 
// si lo que piden es un numero de clusters XX --> primero tomamos
// bloques de 24 si hacemos los bloques mas grandes vamos a tener menos clusters.?
// podemos tomar un porcentaje de referencia, por ejemplo 80 % de igualdad de docs. y lo bajamos hasta 50 %.
// si no hay la cantidad de clusters deseada disminuimos el tam del bloque. (esto hay que irlo probando)

// si no dan numero de clusters dado, tenemos que buscar el optimo viendo el punto donde de tener muchos clusters pasamos
// a tener uno solo.
void buscarCandidat(int** matrizHM, int numeroDeDocsTotales) {
	int tamanios[8] = {2,3,4,6,8,12,16,24};
	
	vector<Cluster> clusters;
	
	int tamBloque = 24, comienzo = 0;
	bool candidatos;
	while (comienzo < FUNCIONES_HASH) {
		for (int doc = 0; doc < numeroDeDocsTotales; doc++) {
			for (int docAComp = (doc+1);docAComp < numeroDeDocsTotales; docAComp++) {
				candidatos = true;
				for (int funcHash = comienzo; funcHash < (tamBloque+comienzo); funcHash++) {
					if (matrizHM[doc][funcHash] != matrizHM[docAComp][funcHash]) {candidatos = false; break; }
					}
				if (candidatos) {
					if (!estanEnCluster(doc,docAComp)) crearNuevoCluster(doc,docAComp); //estanEnClusters guarda un el doc que no este en el cluster.				
					}
				} 
			}
			comienzo+=tamBloque;
		}
	unificarClusters(clusters); // ve si hay documentos repetidos en los clusters y une esos clusters o no dependiendo
	// de si los documentos se pueden repetir en los clusters o no (opcion que se entre por consola).
}

// habria que ver si con esto es necesario o hay que modificar la matriz de hashmin fucionando los documentos que estan en
// loos clusters. esto es, para esos documentos, poner el minimo correspondiente a cada func de hashing.

int main() {
	int tamanios[8] = {2,3,4,6,8,12,16,24};
	cout << tamanios[3]<<endl;
	return 0;
}


